//
//  IOMonad+Scheduler.swift
//  iOSDemo
//
//  Created by FH on 2020/9/30.
//  Copyright © 2020 Fuhan. All rights reserved.
//

import Foundation

public class IOScheduler {
    private static let customQueue = DispatchQueue(label: "RACSchedule::Queue::Concurrent", qos: .background, attributes: .concurrent)
    fileprivate let queue: DispatchQueue
    
    private init(inMain: Bool) {
        self.queue = inMain ? .main : Self.customQueue
    }
    
    public static var main: IOScheduler {
        return IOScheduler(inMain: true)
    }
    
    public static var scheduler : IOScheduler {
        return IOScheduler(inMain: false)
    }
}

extension IOMonad {
    func deliverOnSchedule(_ runInMainThread: Bool=false) -> IOMonad {
        return IOMonad<T> { thunker in
            let schedule = runInMainThread ? IOScheduler.main : IOScheduler.scheduler
            let composeDisposer = IODisposer()
            let preDisposer = self.enableValueSemantics().subscribe(nextFn: { val in
                schedule.queue.async {
                    thunker.sendNext(val)
                }
            }, completeFn: {
                schedule.queue.async {
                    thunker.sendComplete()
                }
            }) { err in
                schedule.queue.async {
                    thunker.sendError(err)
                }
            }
            composeDisposer.setDispose {
                preDisposer.dispose()
            }

            return composeDisposer.dispose
        }.debugName("schedue\(runInMainThread ? " main" : " background")")
    }
    
    func deliverOnMainThread() -> IOMonad {
        return self.deliverOnSchedule(true)
    }
}

public func timer(_ interval: Double,
                  delay: Double = -1,
                  schedule: IOScheduler = IOScheduler.main) -> IOMonad<Date> {
    return IOMonad { thunker in
        // delay == -1，表示Delay时间同interval，该行为与RAC相同。delay == 0，表示无需等待
        let delayTime = DispatchTime.now() + (delay < 0 ? interval : delay)
        let timer = DispatchSource.makeTimerSource(queue: schedule.queue)
        timer.schedule(deadline: delayTime, repeating: interval)
        timer.setEventHandler {
            thunker.sendNext(Date())
        }
        timer.resume()
        
        return {
            timer.cancel()
            // TODO: remove
            print("### timer dispose .")
        }
    }.debugName("timer")
}

public func onceTimer(_ interval: Double) -> IOMonad<Date> {
    return timer(interval).take(1)
}
